package com.music.glide.load.model

import java.lang.StringBuilder

/**
 * LazyHeaders 是一个用于构造和管理 HTTP 请求头部的类。
 * 它的特点是 惰性加载：某些头部的值可以在实际请求时动态生成，而不是在构建请求时立即确定。
 * 支持 线程安全：通过双重检查锁机制 (double-checked locking) 确保头部生成的线程安全性。
 */
class KLazyHeaders(private val headers: Map<String, List<KLazyHeaderFactory>>? = null) : KHeaders {

    private var combineHeaders: Map<String, String>? = null


    override fun getHeader(): Map<String, String> {
        if (combineHeaders == null) {
            synchronized(this) {
                if (combineHeaders == null) {
                    combineHeaders = generateHeaders()
                }
            }
        }
        return combineHeaders!!
    }

    private fun generateHeaders(): Map<String, String> {
        val map = mutableMapOf<String, String>()
        headers?.forEach {
            buildHeaderValue(it.value).apply {
                if (isNotEmpty()) {
                    map.put(it.key, this)
                }
            }
        }
        return map
    }

    private fun buildHeaderValue(factories: List<KLazyHeaderFactory>): String {
        val sb = StringBuilder()
        factories.forEachIndexed { index, value ->
            value.buildHeader().apply {
                if (isNotEmpty()) {
                    sb.append(this)
                }
            }
            if (index != factories.size - 1) {
                sb.append(",")
            }
        }
        return sb.toString();
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as KLazyHeaders

        if (headers != other.headers) return false

        return true
    }

    override fun hashCode(): Int {
        return headers?.hashCode() ?: 0
    }

    class Builder {
        private var copyOnModify = true
        private var isUserAgentDefault = true
        private var headers = DEFAULT_HEADERS

        fun addHeader(key: String, value: String) {
            addHeader(key, StringHeaderFactory(value))
        }

        fun addHeader(key: String, factory: KLazyHeaderFactory): Builder {
            if (!isUserAgentDefault && DEFAULT_USER_AGENT.equals(key, ignoreCase = true)) {
                return setHeader(key, factory)
            }
            copyIfNecessary()
            getFactories(key).add(factory)
            return this
        }

        fun setHeader(key: String, value: String?) {
            setHeader(key, if (value == null) null else StringHeaderFactory(value))
        }

        fun setHeader(key: String, factory: KLazyHeaderFactory?): Builder {
            copyIfNecessary()
            if (factory == null) {
                headers.remove(key)
            } else {
                getFactories(key).apply {
                    clear()
                    add(factory)
                }
            }
            if (isUserAgentDefault && USER_AGENT_HEADER.equals(key, ignoreCase = true)) {
                isUserAgentDefault = false
            }
            return this
        }

        fun build(): KLazyHeaders {
            copyOnModify = true
            return KLazyHeaders(headers)
        }

        private fun getFactories(key: String): MutableList<KLazyHeaderFactory> {
            var factorier = headers[key]
            if (factorier == null) {
                factorier = mutableListOf()
                headers.put(key, factorier)
            }
            return factorier
        }

        private fun copyIfNecessary() {
            if (copyOnModify) {
                copyOnModify = false
                headers = copyHeaders()
            }
        }

        private fun copyHeaders(): MutableMap<String, MutableList<KLazyHeaderFactory>> {
            val result = mutableMapOf<String, MutableList<KLazyHeaderFactory>>()
            headers.forEach {
                result[it.key] = mutableListOf(*(it.value.toTypedArray()))
            }
            return result
        }

        companion object {
            private const val USER_AGENT_HEADER = "User-Agent"
            private var DEFAULT_USER_AGENT = getSanitizedUserAgent()
            private var DEFAULT_HEADERS: MutableMap<String, MutableList<KLazyHeaderFactory>>

            init {
                DEFAULT_HEADERS = mutableMapOf<String, MutableList<KLazyHeaderFactory>>().apply {
                    if (!DEFAULT_USER_AGENT.isNullOrEmpty()) {
                        put(
                            USER_AGENT_HEADER,
                            mutableListOf(StringHeaderFactory(DEFAULT_USER_AGENT!!))
                        )
                    }
                }
            }

            private fun getSanitizedUserAgent(): String? {
                val defaultAgent = System.getProperty("http.agent")
                if (defaultAgent.isNullOrEmpty()) {
                    return defaultAgent
                }
                val sb = StringBuilder(defaultAgent.length)
                defaultAgent.forEach {
                    if ((it > '\u001f' || it == '\t') && it < '\u007f') {
                        sb.append(it)
                    } else {
                        sb.append("?")
                    }
                }
                return sb.toString()
            }
        }
    }


    class StringHeaderFactory(private val value: String) : KLazyHeaderFactory {
        override fun buildHeader(): String {
            return value
        }

        override fun toString(): String {
            return "StringHeaderFactory(value='$value')"
        }

        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as StringHeaderFactory

            if (value != other.value) return false

            return true
        }

        override fun hashCode(): Int {
            return value.hashCode()
        }

    }
}